#!/usr/bin/env ruby

LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))

require "#{LKP_SRC}/lib/dmesg"
require "#{LKP_SRC}/lib/string_ext"
require "#{LKP_SRC}/lib/log"

error_ids = {}

$ignore_patterns = [
  '^\++ .*',   # etc/ignore-stderr/bash-x
]
$catch_patterns = []
$catch_files = []

def load_meta_patterns(program)
  file = "#{LKP_SRC}/programs/#{program}/meta.yaml"
  return unless File.exist? file

  meta = YAML.load_file(file)
  if meta['stderr'].is_a? Hash
    if meta['stderr']['ignore-regex'].is_a? Array
      meta['stderr']['ignore-regex'].each do |line| $ignore_patterns << Regexp.new(line.chomp) end
    end

    if meta['stderr']['catch-regex'].is_a? Array
      meta['stderr']['catch-regex'].each do |line|
        $catch_patterns << '-e'
        $catch_patterns << line.chomp
      end
    end

    f = meta['stderr']['catch-files']
    if f.is_a? Array
      $catch_files.concat f
    elsif f.is_a? String
      $catch_files.concat f.split
    end
  end
end

def load_etc_patterns(program)
  file = "#{LKP_SRC}/etc/ignore-stderr/#{program}"
  return unless File.exist? file

  File.open(file).each_line do |line|
    line = line.resolve_invalid_bytes
    $ignore_patterns << Regexp.new(line.chomp)
  end
end

def should_ignore_stderr(line)
  line = line.resolve_invalid_bytes
  $ignore_patterns.any? do |re|
    # ERR in `match': invalid byte sequence in US-ASCII (ArgumentError)
    # treat unrecognized line as "can't be ignored"

    re.match line
  rescue StandardError
    nil
  end
end

def get_workloads
  if ENV['JOB_PP_KEYS']
    return ENV['JOB_PP_KEYS']
  elsif File.exist? "#{ENV['TMP']}/executed_programs"  # when run in testbox
    return File.read("#{ENV['TMP']}/executed_programs")
  elsif File.exist? "#{ENV['RESULT_ROOT']}/executed_programs"
    return File.read("#{ENV['RESULT_ROOT']}/executed_programs")
  else
    return ''
  end
end

debug_mode = false

get_workloads.split.each do |program|
  load_meta_patterns program # new layout
  load_etc_patterns program  # old layout for compatibility
end

if ENV['RESULT_ROOT']
  cmd = %w(grep -s -h -i -f) + ["#{LKP_SRC}/etc/stderr-pattern"] + $catch_patterns + $catch_files +
            ["#{ENV['RESULT_ROOT']}/stderr",
             "#{ENV['RESULT_ROOT']}/stdout",
            ]
  lines = IO.popen(cmd).readlines
else
  lines = $stdin.readlines
end

lines.each do |line|
  line.strip!

  debug_mode = true if line.start_with?('+') && line.include?("'")
  if debug_mode && line.end_with?("'")
    debug_mode = false
    next
  end
  next if debug_mode

  next if should_ignore_stderr(line)

  # ERR: lib/dmesg.rb:151:in `gsub!': invalid byte sequence in US-ASCII (ArgumentError)
  line = line.resolve_invalid_bytes.strip_nonprintable_characters

  if line =~ /\/tmp\/rpm-tmp\.[0-9a-zA-Z#]{6}\b(.*)/
    line = '/tmp/rpm-tmp/' + $1
  end

  id = common_error_id(line)

  next if id.size < 3

  # Don't treat the lines starting with
  # Date/Num/Hex Num/SHA as comments
  id.gsub!(/^#/, '_#') if line[0] != '#'

  error_ids[id] = line
end

error_ids.each do |id_, line_|
  puts "eid.#{id_}: 001"
  puts "msg.#{id_}.message: #{line_.inspect}"
  puts
end

puts 'eid.has_stderr: 001' unless error_ids.empty?

log_warn "noisy stderr, check #{ENV['RESULT_ROOT']}/stderr" if error_ids.size > 100
